package  
{
	import org.flixel.*;
	import flash.display.BitmapData;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * ...
	 * @author Jay Wagner
	 */
	public class PlayState extends FlxState 
	{
		public static const UNFINISHED:uint = 0;
		public static const BRONZE:uint = 1;
		public static const SILVER:uint = 2;
		public static const GOLD:uint = 3;
		
		public static const UNKNOWN:uint = 0;
		public static const TIMEUP:uint = 1;
		public static const ALLLIGHTSLIT:uint = 2;
		public static const ALLPOWERGONE:uint = 3;
		
		//protected const NO_RAIN:uint = 0;
		//protected const RAINING_DOWN:uint = 1;
		//protected const RAINING_LEFT:uint = 2;
		//protected const RAINING_RIGHT:uint = 3;
		//protected const RAIN_DOWN_TIME:Number = 10.0;
		//protected const RAIN_LEFTRIGHT_TIME:Number = 5.0;
		
		public static var whyLevelEnded:uint = UNKNOWN;
		
		//values for all level awards
		public static const _level0Bronze:uint = 226;
		public static const _level0Silver:uint = 2500;
		public static const _level0Gold:uint = 3750;
		public static const _level1Bronze:uint = 1;
		public static const _level1Silver:uint = 3500;
		public static const _level1Gold:uint = 5250;
		public static const _level2Bronze:uint = 1;
		public static const _level2Silver:uint = 5000;
		public static const _level2Gold:uint = 6800;
		public static const _level3Bronze:uint = 1;
		public static const _level3Silver:uint = 3750;
		public static const _level3Gold:uint = 4500;
		public static const _level4Bronze:uint = 1;
		public static const _level4Silver:uint = 4050;
		public static const _level4Gold:uint = 5100;
		
		public static var desaturation:Number = 1;
		public static var maxDesaturationLevel:uint = 0;
		public static var currentDesurationLevel:uint = 0;
		
		protected var _background:FlxSprite;
		
		public var lightning:Lightning;
		public var lightBulbsDisplay:LightBulbCounter;
		public var timerDisplay:LevelTimer;
		public var tilemap:FlxTilemapExt;
		public var objectmap:FlxTilemapExt;
		public var movermap:FlxTilemapExt;
		public var lightningmap:FlxTilemapExt;
		public var conveyorBelts:FlxGroup;
		public var lightBulbs:FlxGroup;
		public var moverGroup:FlxGroup;
		public var powerups:FlxGroup;
		public var levels:Array;
		
		//set value to change delay on last light being hit to level over screen.
		protected var _lastLightEndLevelDelay:Number = 4.0;
		
		protected var _levelTime:int = 0;
		protected var _playerStartingX:int = 0;
		protected var _playerStartingY:int = 0;
		protected var _powerGauge:PowerGauge;
		
		public var pauseButton:FlxButton;
		public var soundButton:FlxButton;
		public var pauseSprite:FlxSprite;
		public var soundSprite:FlxSprite;
		public var noSoundSprite:FlxSprite;
		
		public var playerTorso:PlayerTorso;
		public var playerGun:PlayerGun;
		
		protected var _playerGroup:FlxGroup;
		protected var _mapGroup:FlxGroup;
		
		protected var _levelTransition:LevelTransition;
		
		//protected var _raining:uint = NO_RAIN;
		//protected var _rainShiftLeft:Boolean = true;
		//protected var _rainTimer:Number = 0.0;
		//protected var _rainUL:FlxSprite;
		//protected var _rainUR:FlxSprite;
		//protected var _rainLL:FlxSprite;
		//protected var _rainLR:FlxSprite;

		protected var timeAlmostUpTrigger:Boolean = false		
		private var _counter:Number = 0;
		//private var _numberOfBatteries:uint = 999; //so number resets on first update
		
		private var _fadeSprite:FlxSprite;
		private const _fadeInTime:Number = 0.2;
		private var _fadeInCounter:Number = 0.0;
		private const _fadeOutTime:Number = 3.0;
		private var _fadeOutCounter:Number = 0.0;
		
		public static var isLevelTransitioning:Boolean = false;
		
		override public function create():void
		{
			FlxG.mouse.show();
			
			isUIVisible = true;
			isLevelTransitioning = false;
			
			moverGroup = new FlxGroup();
			conveyorBelts = new FlxGroup;
			
			tilemap = new FlxTilemapExt();
			objectmap = new FlxTilemapExt();
			movermap = new FlxTilemapExt();
			lightningmap = new FlxTilemapExt();
			_mapGroup = new FlxGroup();
			
			//create and add new tilemap
			tilemap.auto = FlxTilemap.OFF;
			
			_mapGroup.add(tilemap);
			_mapGroup.add(moverGroup);
			_mapGroup.add(conveyorBelts);
			add(_mapGroup);
			
			powerups = new FlxGroup();
			add(powerups);
			
			_playerGroup = new FlxGroup();			
			playerTorso = new PlayerTorso(0, 0);
			playerGun = new PlayerGun(0, 0);
			_playerGroup.add(playerTorso);
			_playerGroup.add(playerGun);
			add(_playerGroup);
			
			FlxG.follow(playerTorso, 3);
			
			lightning = new Lightning();
			add(lightning);
			
			lightBulbs = new FlxGroup();
			add(lightBulbs);
			
			//if (_raining != NO_RAIN) 
			//{
				//_rainUL = new FlxSprite(0, -FlxG.height, ImageFiles.rain);
				//_rainUR = new FlxSprite(FlxG.width, -FlxG.height, ImageFiles.rain);
				//_rainLL = new FlxSprite(0, 0, ImageFiles.rain);
				//_rainLR = new FlxSprite(FlxG.width, 0, ImageFiles.rain);
				//
				//_rainUL.scrollFactor.x = _rainUL.scrollFactor.y = _rainUR.scrollFactor.x = _rainUR.scrollFactor.y = 0;
				//_rainLL.scrollFactor.x = _rainLL.scrollFactor.y = _rainLR.scrollFactor.x = _rainLR.scrollFactor.y = 0;
				//_rainUL.velocity.y = _rainUR.velocity.y = _rainLL.velocity.y = _rainLR.velocity.y = 200;
				//
				//add(_rainUL);
				//add(_rainUR);
				//add(_rainLL);
				//add(_rainLR);
			//}
			
			_powerGauge = new PowerGauge(FlxG.width / 2 - 50, 0);
			add(_powerGauge);
			
			timerDisplay = new LevelTimer(0);
			add(timerDisplay.timerText);
			
			lightBulbsDisplay = new LightBulbCounter();
			add(lightBulbsDisplay.lightBulbText);
			add(lightBulbsDisplay.pauseText);
			
			pauseButton = new FlxButton(FlxG.width / 2 - 178, 0, onPause);
			pauseSprite = new FlxSprite(0, 0, ImageFiles.pauseButton);
			pauseButton.scrollFactor.x = pauseButton.scrollFactor.y = 0;
			pauseButton.loadGraphic(pauseSprite);
			add(pauseButton);
			
			soundButton = new FlxButton(FlxG.width / 2 + 156, 0, onMute);
			soundSprite = new FlxSprite(0, 0, ImageFiles.soundButton);
			noSoundSprite = new FlxSprite(0, 0, ImageFiles.noSoundButton);
			soundButton.scrollFactor.x = soundButton.scrollFactor.y = 0;
			if (FlxG.mute)
			{
				soundButton.loadGraphic(noSoundSprite);
			}
			else
			{
				soundButton.loadGraphic(soundSprite);
			}
			add(soundButton);
			
			_fadeSprite = new FlxSprite().createGraphic(640, 480, 0xff000000);
			_fadeSprite.scrollFactor.x = _fadeSprite.scrollFactor.y = 0;
			_fadeSprite.alpha = 1;
			add(_fadeSprite);
			
			_levelTransition = new LevelTransition();
			add(_levelTransition);
		}
		
		override public function update():void
		{
			if (_fadeInCounter < _fadeInTime)
			{
				_fadeInCounter += FlxG.elapsed;
				_fadeSprite.alpha = Math.abs(1 - (_fadeInCounter / _fadeInTime))
			}
			
			if (timerDisplay.time < 10 && !timeAlmostUpTrigger)
			{
				timeAlmostUpTrigger = true;
				FlxG.playMusic(SoundFiles.timeUpMusic);
			}
			
			if (!isUIVisible)
			{
				_powerGauge.visible = false;
				timerDisplay.clockFaceSprite.visible = false;
				timerDisplay.nextClockFaceSprite.visible = false;
				timerDisplay.timerText.visible = false;
				timerDisplay.clockHandSprite.visible = false;
				lightBulbsDisplay.lightBulbText.visible = false;
				lightBulbsDisplay.pauseText.visible = false;
				lightBulbsDisplay.lightBulbPic.visible = false;
				pauseButton.visible = false;
				soundButton.visible = false;
			}
			else
			{
				_powerGauge.visible = true;
				timerDisplay.clockFaceSprite.visible = true;
				timerDisplay.nextClockFaceSprite.visible = true;
				timerDisplay.timerText.visible = true;
				timerDisplay.clockHandSprite.visible = true;
				lightBulbsDisplay.lightBulbText.visible = true;
				lightBulbsDisplay.pauseText.visible = true;
				lightBulbsDisplay.lightBulbPic.visible = true;
				pauseButton.visible = true;
				soundButton.visible = true;
			}
			
			if (isLevelOver())
			{
				if (_fadeOutCounter < _fadeOutTime)
				{
					isLevelTransitioning = true;
					
					lightning.StopFiring();
					
					if (_fadeOutCounter < _fadeOutTime)
					{
						_fadeOutCounter += FlxG.elapsed;
						
						_fadeSprite.alpha = _fadeOutCounter / _fadeOutTime;
						
						//makes all bulb bars dissappear after level ends
						for (var i:uint = 0; i < lightBulbs.members.length; i++)
						{
							var bulb:LightBulb = lightBulbs.members[i] as LightBulb;
							bulb.glow.alpha -= FlxG.elapsed / 2;
							bulb.powerBarBackground.alpha -= FlxG.elapsed / 2;
							bulb.powerBarLevel1.alpha -= FlxG.elapsed / 2;
							bulb.powerBarLevel2.alpha -= FlxG.elapsed / 2;
							bulb.powerBarLevel3.alpha -= FlxG.elapsed / 2;
						}
					}
					
					//for (var i:int = 0; i < lightBulbs.members.length; i++)
					//{
						//var bulb:LightBulbObject = lightBulbs.members[i] as LightBulbObject;
						//bulb.decreaseTimer.stop();
					//}
					
					// Initiate level transition screen
					if (!_levelTransition.exists)
					{
						_levelTransition.InitiateTransition();
					}
				}
				_levelTransition.update();
			}
			else
			{
				//if (_numberOfBatteries == 999)
				//{
					//_numberOfBatteries = 0;
					//
					//for (var i:uint = 0; i < powerups.members.length; i++)
					//{
						//if (powerups.members[i]._isBattery == true)
						//{
							//_numberOfBatteries++;
						//}
					//}
				//}
				
				lightBulbsDisplay.Update(lightBulbs);
				timerDisplay.Update();
				
				super.update();					//inherited class update function
				
				if (playerGun.x != playerTorso.x + playerTorso.width / 2)
				{
					if (playerTorso.facing == FlxSprite.LEFT)
					{
						playerGun.x = playerTorso.x + 12;
					}
					else
					{
						playerGun.x = playerTorso.x + 15;
					}
				}
				if (playerGun.y != playerTorso.y)
				{
					playerGun.y = playerTorso.y + 7;
				}
				
				//Sets the player facing based on mouse position
				if (FlxG.mouse.x > playerTorso.x + playerTorso.width / 2)
				{
					playerTorso.setFacingRight();
					playerGun.setFacingRight();
				}
				else
				{
					playerTorso.setFacingLeft();
					playerGun.setFacingLeft();
				}
				
				playerTorso.maintainScreenBounds(tilemap.left, tilemap.right);
				playerTorso.updateCollisionBounds();
				FlxU.overlap(playerTorso, powerups, overlapPlayerPowerup);
				FlxU.collide(_mapGroup, lightning.sparkEmitter);
				FlxU.collide(_mapGroup, lightning.bulbSparkEmitter);
				FlxU.collide(_mapGroup, _playerGroup);
				FlxU.collide(moverGroup, _playerGroup);
			}
		}
		
		public static function calculateRating(levelScore:uint, levelNumber:uint):uint
		{
			switch (levelNumber)
			{
				case 0:
				return determineRating(levelScore, _level0Bronze, _level0Silver, _level0Gold);
				case 1:
				return determineRating(levelScore, _level1Bronze, _level1Silver, _level1Gold);
				case 2:
				return determineRating(levelScore, _level2Bronze, _level2Silver, _level2Gold);
				case 3:
				return determineRating(levelScore, _level3Bronze, _level3Silver, _level3Gold);
				case 4:
				return determineRating(levelScore, _level4Bronze, _level4Silver, _level4Gold);
				default:
				return 0;
			}
		}
		
		public static function determineRating(score:uint, bronze:uint, silver:uint, gold:uint):uint
		{
			if (score < bronze)
			{
				return UNFINISHED;
			}
			else if (score < silver)
			{
				return BRONZE;
			}
			else if (score < gold)
			{
				return SILVER;
			}
			else
			{
				return GOLD;
			}
		}
		
		public function setSepia(obj:BitmapData, desat:Number):BitmapData
		{	
			//var rLum:Number = 0.34;
			//var gLum:Number = 0.34;
			//var bLum:Number = 0.34;
			
			// Some other constants for modifying the appearance of the greyscale effect
			var rLum:Number = 0.212671;
			var gLum:Number = 0.715160;
			var bLum:Number = 0.072169;
			
			//var rLum:Number = .3086;
			//var gLum:Number = .6094;
			//var bLum:Number = .0820;
		 
			var matrix:Array = [	desat * rLum + 1 - desat, desat * gLum,             desat * bLum,             0, desat * 30,
									desat * rLum,             desat * gLum + 1 - desat, desat * bLum,             0, desat * 20,
									desat * rLum,             desat * gLum,             desat * bLum + 1 - desat, 0, 0,
									0, 0, 0, 1, 0 ];		 
			
			var filter:ColorMatrixFilter = new ColorMatrixFilter( matrix );
			obj.applyFilter( obj, new Rectangle(0, 0, obj.width, obj.height ), new Point(0, 0), filter );	
			
			return obj;
		}
		
		// This is the new hotness!  This is essentially a callback from the game rendering loop,
		// letting us know that all the game rendering has finished,
		// and that FlxState.screen has been filled with the game's visual contents.
		override public function postProcess():void
		{
			if (isUIVisible)
			{
				desaturation = currentDesurationLevel / maxDesaturationLevel;
				screen.pixels = setSepia(screen.pixels, desaturation);
			}
			//screen.draw(_playerTorso, _playerTorso.x + FlxG.scroll.x, _playerTorso.y + FlxG.scroll.y);
			//screen.draw(_playerGun, _playerGun.x + FlxG.scroll.x, _playerGun.y + FlxG.scroll.y);
			
			//_powerGauge.redraw();
		}
		
		public function restartLevel():void
		{
			FlxG.score = 0;
			
			_levelTransition.exists = false;
			
			playerTorso.x = _playerStartingX;
			playerTorso.y = _playerStartingY;
			
			timerDisplay.setTimerValue(_levelTime);
			
			PowerGauge.currentVolts = PowerGauge.maxVolts;
			
			for (var i:int = 0; i < lightBulbs.members.length; i++)
			{
				var bulb:LightBulb = lightBulbs.members[i] as LightBulb;
				bulb.DrainAllPower();
			}
			
			lightBulbsDisplay.displayLightBulbCount(lightBulbs);
			maxDesaturationLevel  = lightBulbs.members.length * 3;
			currentDesurationLevel = maxDesaturationLevel;
		}
		
		protected function overlapPlayerPowerup(player:PlayerTorso, powerup:Powerup):void
		{
			powerup.collect();
			
			powerup.kill();
		}
		
		protected function isLevelOver():Boolean
		{
			if (!timerDisplay.isTimeLeft())
			{
				timerDisplay.clockFaceSprite.play("twelve");
				whyLevelEnded = TIMEUP;
				
				return true;
			}
			else if (lightBulbsDisplay.litCount == lightBulbsDisplay.totalLightbulbs())
			{
				timerDisplay.pauseTimer();
				
				//trace(_counter);
				_counter += FlxG.elapsed;
				
				if (_counter >= _lastLightEndLevelDelay)
				{
					whyLevelEnded = ALLLIGHTSLIT;
					
					return true;
				}
				else
				{
					return false;
				}
			}
			else if (isAllPowerGone())
			{
				_powerGauge.update();
				lightBulbs.update();
				
				whyLevelEnded = ALLPOWERGONE;
				
				return true;
			}
			else
			{
				return false;
			}
		}
		
		protected function isAllPowerGone():Boolean //returns true if ALL powerups are gone
		{
			var isBatteries:Boolean = false;
			
			for (var i:int = 0; i < powerups.members.length; i++)
			{
				var p:Powerup = powerups.members[i] as Powerup;
				
				if (p.isBattery && p.exists)
				{
					isBatteries = true;
					break;
				}
			}
			
			if (PowerGauge.currentVolts == 0 && !isBatteries)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		
		protected function onPause():void
		{
			if (!isLevelTransitioning)
			{
				lightning.StopFiring();
				FlxG.setPause(!FlxG.pause);
			}
		}
		
		protected function onMute():void 
		{
			if (!isLevelTransitioning)
			{
				if (FlxG.mute)
				{
					soundSprite.x = soundButton.x;
					soundSprite.y = soundButton.y;
					soundButton.loadGraphic(soundSprite);
				}
				else
				{
					noSoundSprite.x = soundButton.x;
					noSoundSprite.y = soundButton.y;
					soundButton.loadGraphic(noSoundSprite);
				}
				FlxG.mute = !FlxG.mute;
			}
		}
	}

}